package tools;

import com.google.protobuf.DescriptorProtos;
import com.google.protobuf.GeneratedMessage;
import com.google.protobuf.Message;
import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import org.reflections.Reflections;
import org.reflections.scanners.SubTypesScanner;
import org.reflections.scanners.TypeAnnotationsScanner;
import org.reflections.util.ClasspathHelper;
import org.reflections.util.ConfigurationBuilder;

@Slf4j
public class MessageManager {

    private static final Map<Integer, GeneratedMessage> msgId2MsgMap = new HashMap<>();
    private static final Map<Class<?>, Integer> msgClazz2MsgIdMap = new HashMap<>();

    public static void init() {
        try {
            // 构建更精细配置的Reflections对象
            Reflections reflections = new Reflections(new ConfigurationBuilder().setUrls(ClasspathHelper.forPackage("msg"))
                    .setScanners(new TypeAnnotationsScanner(), new SubTypesScanner(false)));

            Set<Class<?>> allClasses = reflections.getSubTypesOf(Object.class);
            Set<Class<?>> msgClassSet = allClasses.stream().filter(clazz -> {
                if (clazz.isMemberClass()) {
                    return false;
                }

                if (clazz.isLocalClass()) {
                    return false;
                }

                if (clazz.getName().contains("$")) {
                    return false;
                }

                if (clazz.getSimpleName().equals("Descriptor") || clazz.getSimpleName().equals("Options")) {
                    return false;
                }

                return true;
            }).collect(Collectors.toSet());


            for (Class<?> clazz : msgClassSet) {
                Class<?>[] innerClazzArray = clazz.getDeclaredClasses();

                for (Class<?> innerClazz : innerClazzArray) {
                    if (!GeneratedMessage.class.isAssignableFrom(innerClazz)) {
                        continue;
                    }
                    GeneratedMessage returnObj = (GeneratedMessage) innerClazz.getDeclaredMethod("getDefaultInstance").invoke(innerClazz);
                    DescriptorProtos.MessageOptions messageOptions = returnObj.getDescriptorForType().getOptions();

                    int msgId = (int) messageOptions.getAllFields().values().iterator().next();

                    if (msgId2MsgMap.putIfAbsent(msgId, returnObj) != null || msgClazz2MsgIdMap.putIfAbsent(innerClazz, msgId) != null) {
                        throw new RuntimeException("msgId=" + msgId + " class=" + innerClazz.getName() + " 定义重复");
                    }
                }
            }

            log.info("MessageManager init done. msgId count={}", msgId2MsgMap.size());
        } catch (Exception e) {
            log.error("MessageManager init error=", e);
        }
    }

    public static Message.Builder getBuilderByMsgCode(int msgId) {
        if (msgId < 0) {
            return null;
        }

        GeneratedMessage msg = msgId2MsgMap.get(msgId);
        if (null == msg) {
            return null;
        }

        return msg.newBuilderForType();
    }

    public static int getMsgIdByMsgClazz(Class<?> msgClazz) {
        if (null == msgClazz) {
            return -1;
        }

        Integer msgCode = msgClazz2MsgIdMap.get(msgClazz);
        if (null != msgCode) {
            return msgCode;
        } else {
            return -1;
        }
    }

    public static Map<Class<?>, Integer> getMsgClazz2MsgIdMap() {
        return msgClazz2MsgIdMap;
    }
}
